/*
 * RemoteDumper.java   2008/09/10
 *
 * Copyright 2008 Web & Zen Multimedia, All rights reserved.
 * Use is subject to license terms.
 */
package it.wzm.lightweightlog;

import it.wzm.lightweightlog.annotation.OpeningProcessor;
import it.wzm.lightweightlogx.ws.LogBean;
import it.wzm.lightweightlogx.ws.LogBeanService;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.LinkedList;
import java.util.Properties;
import javax.xml.namespace.QName;

/**
 * Dump Entry to a remote Web Service
 * @author Leonardo Celati
 */
@OpeningProcessor(keepingalive=false)
public class RemoteDumper extends Dumper {

	/**
	 * As required by serialization
	 */
	private static final long serialVersionUID = -8154275483986618192L;
	/**
	 * Our key which recognize ourselves in remote
	 */
	private String key;
    /**
     * Our web service
     */
	private LogBeanService service;	
	/**
	 * The ejb
	 */
	private LogBean lb;
	/**
	 * Our temporary buffer
	 */
	private LinkedList buffer;
	/**
	 * Max buffer size
	 */
	private int maxbuffer;
	
	/**
	 * The only Constructor
	 * @param p The custom properties
	 */
	public RemoteDumper(Properties p) {
		super(p);
	}	

	/**
	 * In post init we just lookup for the service
	 */
	@Override
	protected void postinit() {
		// see if we have a personal key
		// and some basic check...
		this.key = this.get("key");
		if (key ==null)
			throw new DumperInitializationException("A key is needed");
		
		// if not ask for one...
		// getKey();
		// and store it in our location..
		// store
			
		// let's think about the web service...
        URL url = null;
        try {
            url = new URL(this.get("wsdl"));
        } catch (MalformedURLException e) {
            throw new DumperInitializationException("Malformed url:" + this.get("wsdl"));
        }
        
		// let's init our service...
        try {
			service = new LogBeanService(url,new QName("http://lightweightlogx.wzm.it/", "LogBeanService"));
			lb = service.getLogBeanPort();
			// final check
			if (lb == null) 
				throw new DumperInitializationException("LogBean null");
			
        } catch (RuntimeException e) {
        	throw new DumperInitializationException(e);
        } catch (Exception e){
        	throw new DumperInitializationException(e);
        }

		// initialize buffer...
		try {
			maxbuffer = Integer.parseInt(this.get("maxbuffer"));
		} catch (Exception e) {
			maxbuffer = Constant.DEFAULT_MAXBUFFER;
		}
		buffer = new LinkedList();
	}
	
	/**
	 * This will always return true
	 */
	@Override
	public boolean isOpen() {
		return true;
	}

	/**
	 * Write our Entry to service
	 */
	@Override
	public <E extends Entry> void dump(E e) throws DumperException {
		try {
			// dump entry first...
			lb.dump(key,  e);
			
			// ...then clean our buffer
			if (!buffer.isEmpty()) {
				for (Object x: buffer) {
					lb.dump(key, (Entry)x);
				}
			}
			// cleaning...
			buffer.clear();
			
		} catch (Exception ex) {
			// add to buffer...
			// we will try again later...
			this.addToBuffer(e);
			// then throw error...
			throw new DumperException(ex.getMessage());
		}
	}
	
	/**
	 * Add Entry to our internal buffer
	 * @param <E> Entry
	 * @param e
	 * @return true/false if adding was succesful or not
	 */
	protected <E extends Entry> boolean addToBuffer(E e) {
		
		// perform cleaning...
		while (buffer.size() > maxbuffer)
			buffer.removeFirst();
		
		// our variables...
		FileOutputStream fos = null;
		ObjectOutputStream out = null;
		FileInputStream fis = null;
		ObjectInputStream ois = null;
		File f = null;
		// making a 'Deep copy' of Entry
		try {
			// where the Entry is stored...
			f = File.createTempFile(String.valueOf(e.hashCode() ), ".entry");
			f.deleteOnExit();
			
			// backup....
			fos = new FileOutputStream(f);
			out = new ObjectOutputStream(fos);
			out.writeObject(e);			
		    
			// restore...
			fis = new FileInputStream(f.getPath());
			ois = new ObjectInputStream(fis);
			Entry e_clone = (Entry)ois.readObject();
			
			// adding our copy to buffer...
			return buffer.add(e_clone);
			
		} catch(Exception ex) {
			LogFactory.getLog().warn("Cannot add to buffer " + e.getMessage());
			return false;
		} finally {
			try {
				// final cleaning...
				if (fos != null) fos.close();
				if (out != null) out.close();
				if (fis != null) fis.close();
				if (ois != null) ois.close();
				if (f!=null) f.delete();
			} catch (Exception x) {
				// nothing :-)
			}
		}
	}


	@Override
	public void close() throws DumperException {
	}

	@Override
	public void open() throws DumperException {		
	}	
	

}
